﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

using breakoutsharp.core;
using breakoutsharp.input;
using breakoutsharp.visual;
using breakoutsharp.visual.menu;
using breakoutsharp.visual.gameobject;

namespace breakoutsharp
{
	public partial class MainForm : Form
	{
		/* fundamental variables */
		protected Device device = null;
		protected BreakoutEngine game = null;
		protected Renderer rendering = null;

		/* graphic/vertex variables */
		protected DxStartMenu menu;

		/* screen and camera varaiable */
		protected Size resolution = new Size(800, 600);
		protected Color bgColor = Color.Green;


		/* Fonts */
		protected Microsoft.DirectX.Direct3D.Font menuFont;
		protected Microsoft.DirectX.Direct3D.Font littleFont;

		/* Used for input */
		protected DxKeyboard keyboard;

		/* Game loop variables */
		protected int lastGameUpdateTime = Environment.TickCount;
		protected bool pauseKeyIsDown = false;
		protected int gameStartedTime;
		protected utility.QueryPerfCounter counter = new breakoutsharp.utility.QueryPerfCounter();

		/// <summary>
		/// Default constructor
		/// </summary>
		public MainForm()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Initializes the form and all its components
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void MainForm_Load(object sender, EventArgs e)
		{
			/* Initialize the size of form and prevent windows from drawing the form */
			this.SetClientSizeCore(1200, 900);
			this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque | ControlStyles.UserMouse, true);

			/* Initilaize graphics and vertices/textures */
			InitializeGraphics();

			/* initialize the engine */
			game = new BreakoutEngine(this.Handle, resolution);
			rendering = new Renderer(game, device, this.Size, this.resolution);

			/* Loading a level */
			game.LoadLevel("lvl08");
			game.SetNumberOfPlayers(2);

			/* Setup the camera angle */
			rendering.SetupCamera();

			/* Setup the keyboard */
			keyboard = new DxKeyboard(this);

			/* Create fonts */
			menuFont = new Microsoft.DirectX.Direct3D.Font(device, 30, 30, FontWeight.Normal, 0, false, CharacterSet.Default, Precision.Default, FontQuality.AntiAliased, PitchAndFamily.DefaultPitch,
			"Calibri");
			littleFont = new Microsoft.DirectX.Direct3D.Font(device, 15, 15, FontWeight.Normal, 1, false, CharacterSet.Default, Precision.Default, FontQuality.AntiAliased, PitchAndFamily.DefaultPitch,
			"Calibri");

			/* initiliaze the menu */
			menu = new DxStartMenu(device, new Point(50, 600));

			/* Create eventhandlers for */
			Application.Idle += new EventHandler(this.OnApplicationIdle);
			this.FormClosing += new FormClosingEventHandler(FormIsClosing);
		}

		void OnApplicationIdle(object sender, EventArgs e)
		{
			if (gameStartedTime == 0)
			{
				menu.OpenMenu();
				gameStartedTime = Environment.TickCount;
			}

			do
			{
				GameLoop();
			}
			while (this.AppIsIdle());
		}

		public bool AppIsIdle()
		{
			utility.Win32.peek_message msg;

			return !utility.Win32.PeekMessage(out msg, IntPtr.Zero, 0, 0, utility.Win32.PM_NOREMOVE);
		}

		private void FormIsClosing(object sender, FormClosingEventArgs e)
		{
			// since the Idle event is static we must unregister the event to prevent memory leak!
			Application.Idle -= new EventHandler(this.OnApplicationIdle);
		}

		/// <summary>
		/// Initializes the device
		/// </summary>
		protected void InitializeGraphics()
		{
			PresentParameters pp = new PresentParameters();
			DisplayMode dm = Manager.Adapters.Default.CurrentDisplayMode;

			bool fullScreen = false;
			{
				pp.SwapEffect = SwapEffect.Discard;
				pp.Windowed = !fullScreen;

				if (fullScreen)
				{
					pp.BackBufferFormat = dm.Format;
					pp.BackBufferCount = 1;
					pp.BackBufferHeight = dm.Height;
					//resolution.Height
					pp.BackBufferWidth = dm.Width;
					//resolution.Width
					pp.PresentationInterval = PresentInterval.Immediate;
				}
			}

			device = new Device(Manager.Adapters.Default.Adapter, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing, pp);
			device.VertexFormat = CustomVertex.PositionTextured.Format;

			Material material = new Material();
			material.Diffuse = Color.White;
			material.Specular = Color.LightGray;
			material.SpecularSharpness = 1.0F;

			device.Material = material;
		}

		/// <summary>
		/// Draws the menu of the intro screen
		/// </summary>
		private void DrawIntroScreen()
		{
			menu.Draw();
		}

		private void DrawGameoverScreen()
		{
			menuFont.DrawText(null, "Game Over!", new Rectangle(150, 350, 1000, 150), DrawTextFormat.SingleLine, Color.Red);
		}

		private void paintComponent()
		{
			device.Clear(ClearFlags.Target, bgColor, 1.0f, 0);
			device.BeginScene();

			/* If extra functionality such as zooming/panning needs to be implemented this call is needed! */
			rendering.SetupCamera();

			switch (game.State)
			{
			case BreakoutEngine.GameState.GameOver:
				rendering.RenderObjects();
				//rendering.RenderGameOver();
				DrawGameoverScreen();
				break;
			case BreakoutEngine.GameState.GameRunning:
				rendering.RenderObjects();
				break;
			case BreakoutEngine.GameState.GameNotStarted:
				//rendering.RenderIntro();
				DrawIntroScreen();
				break;
			}

			device.EndScene();
			device.Present();
			this.Text = string.Format("Frames Per Second: {0}", breakoutsharp.utility.FramerateMonitor.CalculateFramerate());
		}

		private void GameLoop()
		{
			/* Get user input */
			keyboard.Poll();

			foreach (Paddle p in game.Paddles)
			{
				if (keyboard.State[p.Controls.MoveLeft])
				{
					p.Controls.MovingLeft = true;
				}
				else
				{
					p.Controls.MovingLeft = false;
				}


				if (keyboard.State[p.Controls.MoveRight])
				{
					p.Controls.MovingRight = true;
				}
				else
				{
					p.Controls.MovingRight = false;
				}


			}

			if (keyboard.State[Microsoft.DirectX.DirectInput.Key.Escape])
			{
				/* Logic: 
				 *  - main menu -> exit
				 *  - in game -> open in-game menu
				 *  - in main menu sub menu -> go up one level
				 */

				if (game.State == BreakoutEngine.GameState.GameNotStarted)
				{
					this.Close();
				}
				else if (game.State == BreakoutEngine.GameState.GameRunning)
				{
					game.EndGame();
				}
			}

			if (keyboard.State[Microsoft.DirectX.DirectInput.Key.Space])
			{
				menu.OpenMenu();
			}

			if (keyboard.State[Microsoft.DirectX.DirectInput.Key.P])
			{
				if (!pauseKeyIsDown)
				{
					pauseKeyIsDown = true;

					if (game.Paused)
					{
						game.Resume();
					}
					else
					{
						game.Pause();
					}
				}
			}
			else
			{
				pauseKeyIsDown = false;
			}

			/* Running AI */

			/* Moving objects and resolving collisions */
			switch (game.State)
			{
			case BreakoutEngine.GameState.GameRunning:
				counter.Stop();

				game.Update(counter.DurationMilliseconds());//timeSinceLast);

				counter.Start();
				break;
			case BreakoutEngine.GameState.GameNotStarted:
				menu.ControlPressed(keyboard.State[Microsoft.DirectX.DirectInput.Key.DownArrow], keyboard.State[Microsoft.DirectX.DirectInput.Key.UpArrow]);

				if (keyboard.State[Microsoft.DirectX.DirectInput.Key.Return])
				{
					DxButton selected = menu.SelectedItem;


					switch (selected.Text)
					{
					case "Start Game":
						game.StartGame();
						break;
					case "Options":
						break;
					case "Exit Game":
						this.Close();
						break;
					}
				}
				break;
			}

			/* Updating graphics */
			paintComponent();
		}

		/// <summary>
		/// Disposes current bla blab
		/// </summary>
		public new void Dispose()
		{
			/* be a good subclass and call base.dispose */
			base.Dispose();

			/* clean up memory */
			if (device != null)
				device.Dispose();
			device = null;
			if (game != null)
				game.Dispose();
			game = null;
			if (menu != null)
				menu.Dispose();
			menu = null;
			if (menuFont != null)
				menuFont.Dispose();
			menuFont = null;
			if (littleFont != null)
				littleFont.Dispose();
			littleFont = null;
			if (keyboard != null)
				keyboard.Dispose();
			keyboard = null;
			if (rendering != null)
				rendering.Dispose();
			rendering = null;

		}
	}
}
